import React, { ReactElement, useState, useEffect } from 'react'
import { Checkbox } from 'antd'
import style from './index.module.less'
import { AuthoritySchema } from '@src/components/schema/authority'

// 获取子孙节点的id
function getIds (d: AuthoritySchema): string[] {
  let r: string[] = []
  r.push(d.id)
  if (d.children instanceof Array) {
    d.children.forEach(li => {
      r = [...r, ...getIds(li)]
    })
  }
  return r
}

interface BlockProps {
  value: string[]
  node: AuthoritySchema
  onChange: (full: string[], current: string[]) => void
}

function Block ({ value, node, onChange }: BlockProps): ReactElement {
  const [ids, setIds] = useState<string[]>([])
  const [selected, setSelected] = useState<string[]>([])
  const [checked, setChecked] = useState(false)
  const children = node.children instanceof Array ? node.children : []
  children.sort((a, b) => {
    if (a.children instanceof Array && b.children instanceof Array) {
      return a.children.length - b.children.length
    }
    return -1
  })
  useEffect(() => {
    setIds(getIds(node))
  }, [node])
  useEffect(() => {
    const r = []
    for (let i = 0; i < ids.length; i++) {
      if (value.includes(ids[i])) {
        r.push(ids[i])
      }
    }
    setChecked(value.includes(node.id) && ids.length === r.length)
    setSelected(r)
  }, [value, ids])
  return (
    <div className={style.block}>
      <div className={style['title-line']}>
        <label>
          <Checkbox checked={checked} indeterminate={!checked && selected.length > 0} onClick={() => {
            const c = !checked
            setChecked(c)
            if (c) {
              setSelected([...ids])
              onChange(ids, [...ids])
            } else {
              setSelected([])
              onChange(ids, [])
            }
          }} />
          <span className={style['title-text']}>{node.name}</span>
        </label>
      </div>
      <div className={style.line}>
        {
          children.map(li => {
            if (li.children?.length === 0) {
              return <Item value={value} node={li} key={li.id} onChange={v => changeItemSelected(selected, li.id, v, node.id, ids, setSelected, setChecked, onChange)} />
            }
            return <Block value={value} node={li} key={li.id} onChange={(f, c) => changeBlockSelected(f, c, selected, ids, node.id, setSelected, setChecked, onChange)} />
          })
        }
      </div>
    </div>
  )
}

// 改变没子项的菜单
function changeItemSelected (selected: string[], id: string, checked: boolean, pid: string, ids: string[], setSelected: (v: string[]) => void, setChecked: (v: boolean) => void, onChange: (f: string[], c: string[]) => void): void {
  const l = [...selected]
  const index = l.indexOf(id)
  if (checked) {
    if (index === -1) {
      l.push(id)
    }
  } else {
    if (index !== -1) {
      l.splice(index, 1)
    }
  }
  const pIndex = l.indexOf(pid)
  if (pIndex !== -1) {
    l.splice(pIndex, 1)
  }
  if (l.length > 0) {
    l.push(pid)
  }
  if (pIndex === -1 && l.length === ids.length - 1) {
    setChecked(true)
  } else {
    setChecked(false)
  }
  setSelected(l)
  onChange(ids, l)
}

// 改变有子项的菜单
function changeBlockSelected (full: string[], current: string[], selected: string[], ids: string[], pid: string, setSelected: (v: string[]) => void, setChecked: (v: boolean) => void, onChange: (f: string[], c: string[]) => void): void {
  let l = [...selected].filter(li => !full.includes(li))
  l = [...l, ...current].filter(li => li !== pid)
  if (current.length === full.length && l.length === ids.length - 1) {
    setChecked(true)
    l.push(pid)
  } else {
    setChecked(false)
  }
  setSelected(l)
  onChange(ids, l)
}

interface ItemProps {
  value: string[]
  node: AuthoritySchema
  onChange: (v: boolean) => void
}

function Item ({ value, node, onChange }: ItemProps): ReactElement {
  const [checked, setChecked] = useState(false)
  useEffect(() => {
    setChecked(value.includes(node.id))
  }, [value])
  return (
    <div className={style.item}>
      <label>
        <Checkbox checked={checked} onClick={() => { setChecked(!checked); onChange(!checked) }} />
        <span className={style['item-text']}>{node.name}</span>
      </label>
    </div>
  )
}

interface Props {
  value: string[]
  tree: AuthoritySchema[]
  onChange: (v: string[]) => void
}

function Main ({ value, tree, onChange }: Props): ReactElement {
  return (
    <div>
      {tree.map(li => {
        return <Block value={value} node={li} key={li.id} onChange={(f, c) => {
          let l = [...value].filter(li => !f.includes(li))
          l = [...l, ...c]
          onChange(l)
        }} />
      })}
    </div>
  )
}

export default Main
